#include<iostream>
#include<sys/types.h>
#include<sys/time.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<cstdio>
#include<cstring>
#include<fcntl.h>
#include<stdlib.h>
#include<signal.h>
#include<pthread.h>
#include <numeric>
#include<algorithm>
#include<sys/socket.h>
#include<fstream>
#include<sstream>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<memory>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<vector>
#include<utility> //类pair的声明
#include<arpa/inet.h>
#include<sys/wait.h>
#include<functional>
#include <semaphore.h>
#include<jsoncpp/json/json.h>
#include<sys/select.h>
#include<mutex.h>
#include<experimental/filesystem>
#include<jsoncpp/json.h>
#include<memory>
#include"bundle.h"
using std::cout;
using std::endl;
using std::string;
using std::vector;
namespace fs=std::experimental::filesystem;
namespace cloud
{
    class FileUtil
    {
    private:
        string _filename;

    public:
        FileUtil(const string &filename)
            : _filename(filename) {}
        bool Remove()
        {
            if(this->Exists()==true)
            {
                 remove(_filename.c_str());
            }
            return true;
        }
        int64_t FileSize()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                cout << "get file size failed!\n";
                return -1;
            }
            return st.st_size;
        }
        time_t LastATime()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                cout << "get file size failed!\n";
                return -1;
            }
            return st.st_atime;
        }
        time_t LastMTime()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                cout << "get file size failed!\n";
                return -1;
            }
            return st.st_mtime;
        }
        string FileName()
        {
            size_t pos = _filename.find_last_of("/");
            if (pos == string::npos)
                return _filename;
            return _filename.substr(pos + 1);
        }
        bool GetPosLen(string *body, size_t pos, size_t len)
        {
            size_t fsize = this->FileSize();
            if (pos + len > fsize)
            {
                cout << "get file len is error" << endl;
                return false;
            }
            std::ifstream ifs;
            ifs.open(_filename, std::ios::binary);
            if (ifs.is_open() == false)
            {
                cout << "open file failed!\n";
                return false;
            }
            ifs.seekg(pos,std::ios::beg);
            body->reserve(len);
            ifs.read(&(*body)[0],len);
            if(ifs.good()==false)
            {
                cout<<"get file content failed"<<endl;
                return false;
            }
            ifs.close();
            return true;
        }
        bool GetContent(string *body)
        {
            size_t fszie=this->FileSize();
            return GetPosLen(body,0,fszie);
        }
        bool SetContent(const string & body)
        {
            std::ofstream ofs;
            ofs.open(_filename,std::ios::binary);
            if(ofs.is_open()==false)
            {
                cout<<"write open file failed!"<<endl;
                return false;
            }
            ofs.write(&body[0],body.size());    //write接口没有这个文件就创建，反之就进行修改
            if(ofs.good()==false)
            {
                cout<<"write file content failed"<<endl;
                return false;
            }
            return true;
        }
        bool Compress(const string& packname)   //用于获取对应文件的压缩后的文件,packname表示压缩后的文件名
        {
            //获取源文件数据
            string body;
            if(this->GetContent(&body)==false)
            {
                cout<<"compress get file content falied!"<<endl;
                return false;
            }
            //2.对数据进行压缩
            string packed=bundle::pack(bundle::LZIP,body);
            //3.将压缩的数据存储到压缩包文件中
            FileUtil fu(packname);
            if(fu.SetContent(packed)==false)
            {
                cout<<"compress write packed data failed!"<<endl;
                return false;
            }
            return true;
        }
        bool UnCompress(const string& filename) //filename表示解压后的文件名
        {
            //将当前压缩包数据读取出来
            string body;
            if(this->GetContent(&body)==false)
            {
                cout<<"uncompress get file content failed!"<<endl;
                return false;
            }
            //对压缩的数据进行解压缩
            string unpacked=bundle::unpack(body);
            //将解压缩的数据写入到新文件
            FileUtil fu(filename);
            if(fu.SetContent(unpacked)==false)
            {
                cout<<"uncompress write packed data failed!"<<endl;
                return false;
            }
            return true;
        } 
        bool Exists()   //判断目录是否存在
        {
            return fs::exists(_filename);
        }
        bool CreateDirectory()  //创建目录
        {
            if(this->Exists())return true;
            return fs::create_directories(_filename);
        }
        bool ScanDirectory(vector<string>*arry) //arry存放目录中的非目录文件的文件名
        {
            for(auto&p:fs::directory_iterator(_filename))
            {
                if(fs::is_directory(p)==true)   //不对目录文件进行操作
                {
                    continue;
                }
                arry->push_back(fs::path(p).relative_path().string());//relative_path表示带有相对路径的文件名
            }
            return true;
        }
    };
    class JsonUtil
    {
    public:
        static bool Serialize(const Json::Value& root,string *str)  //序列化
        {
            Json::StreamWriterBuilder swb;
            std::unique_ptr<Json::StreamWriter>sw(swb.newStreamWriter());
            std::stringstream ss;
            sw->write(root,&ss);
            *str=ss.str();
            return true;
        }
        static bool UnSerialize(const string& str,Json::Value* root)    //反序列化
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader>cr(crb.newCharReader());
            string err;
            bool ret=cr->parse(str.c_str(),str.c_str()+str.size(),root,&err);
            if(ret==false)
            {
                cout<<"parse error"<<err<<endl;
                return false;
            }
            return true;
        }
    };
};